package me.sdevil507.platform.service.impl;

import com.google.common.collect.Lists;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import me.sdevil507.org.dto.OrgResourceRelDto;
import me.sdevil507.org.dto.OrgRoleResultDto;
import me.sdevil507.org.po.OrgDeptPo;
import me.sdevil507.org.po.QOrgResourcePo;
import me.sdevil507.platform.dto.PlatResourceParamsDto;
import me.sdevil507.platform.dto.PlatResourceResultDto;
import me.sdevil507.platform.mapper.PlatResourceMapper;
import me.sdevil507.platform.po.PlatResourcePo;
import me.sdevil507.platform.po.QPlatResourcePo;
import me.sdevil507.platform.repository.PlatResourceRepository;
import me.sdevil507.platform.service.PlatResourceService;
import me.sdevil507.services.dto.HotLogResultDTO;
import me.sdevil507.supports.jpa.PageParamsDTO;
import me.sdevil507.supports.jpa.SortParamsDTO;
import me.sdevil507.supports.status.ComConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 平台资源表[PlatResourcePo]
 *
 * @author sdevil507
 * created on 2020-06-23 18:43:30
 */
@Service
public class PlatResourceServiceImpl implements PlatResourceService {

    @Resource
    private PlatResourceRepository platResourceRepository;

    @Autowired
    private PlatResourceMapper platResourceMapper;

    @Autowired
    JPAQueryFactory jpaQueryFactory;

    @Override
    public List<PlatResourcePo> readAll() {

        QPlatResourcePo qPlatResourcePo = QPlatResourcePo.platResourcePo;

        // 开启谓语查询条件
        Predicate predicate = qPlatResourcePo.id.isNotNull()
                .and(qPlatResourcePo.parentId.isNull());

        // 排序
        Sort sort = Sort.by(new Sort.Order(Sort.Direction.ASC, "sortNum"));

        // 执行Iterable转换List
        return Lists.newArrayList(platResourceRepository.findAll(predicate, sort).iterator());
    }

    @Override
    public Page<PlatResourcePo> readAllByPage(PlatResourceParamsDto searchParamsDto, PageParamsDTO pageParamsDto, SortParamsDTO sortParamsDto) {
        QPlatResourcePo qPlatResourcePo = QPlatResourcePo.platResourcePo;

        // 开启谓语查询条件
        Predicate predicate = qPlatResourcePo.id.isNotNull()
                .and(qPlatResourcePo.parentId.eq(searchParamsDto.getParentId()));

        String title = searchParamsDto.getTitle();
        if (!StringUtils.isEmpty(title)) {
            predicate = ExpressionUtils.and(predicate, qPlatResourcePo.title.like("%" + title + "%"));
        }

        // 排序
        Sort sort = sortParamsDto.getSort();
        if (null == sort) {
            sort = Sort.by(new Sort.Order(Sort.Direction.ASC, "sortNum"));
        }

        // 执行返回
        Pageable pageable = pageParamsDto.getPageableWithSort(sort);
        return platResourceRepository.findAll(predicate, pageable);
    }

    @Override
    public void create(PlatResourceParamsDto dto) {
        platResourceRepository.save(platResourceMapper.dto2po(dto));
    }

    @Override
    public void update(PlatResourceParamsDto dto) {
        PlatResourcePo po = platResourceRepository.findById(dto.getId()).orElse(null);
        if (null != po) {
            platResourceMapper.updatePoFromDto(dto, po);
            platResourceRepository.save(po);
        }
    }

    @Override
    public void delete(PlatResourceParamsDto dto) {
        platResourceRepository.deleteById(dto.getId());
    }

    @Override
    public String getModuleCode(Long parentId) {
        List<PlatResourcePo> resourcePos = platResourceRepository.findAllByParentIdOrderByCodeDesc(parentId);
        if (null != resourcePos && !resourcePos.isEmpty()) {
            // 如果同级有元素情况下
            String srcCode = resourcePos.get(0).getCode();
            String prefixStr = srcCode.substring(0, srcCode.length() - 2);
            String tempValStr = srcCode.substring(srcCode.length() - 2);
            return prefixStr + String.format("%02d", Integer.parseInt(tempValStr) + 1);
        } else {
            // 如果同级没有元素情况下
            PlatResourcePo platResourcePo = platResourceRepository.findById(parentId).orElse(null);
            if (platResourcePo != null) {
                return platResourcePo.getCode() + String.format("%02d", 1);
            }
            return null;
        }
    }

    @Override
    public List<PlatResourcePo> readOrgModules() {
        QPlatResourcePo qPlatResourcePo = QPlatResourcePo.platResourcePo;
        Predicate predicate = qPlatResourcePo.id.isNotNull()
                .and(qPlatResourcePo.parentId.eq(0L).and(qPlatResourcePo.classify.eq(ComConstant.ModuleTerminal.ORGANIZATION)));
        // 执行Iterable转换List
        return Lists.newArrayList(platResourceRepository.findAll(predicate).iterator());
    }

    @Override
    public List<PlatResourceResultDto> findAllByPathList(List<String> pathList) {

        QPlatResourcePo qPlatResourcePo = QPlatResourcePo.platResourcePo;

        return jpaQueryFactory.select(qPlatResourcePo.title, qPlatResourcePo.path, qPlatResourcePo.iconSvg)
                .from(qPlatResourcePo)
                .where(qPlatResourcePo.path.in(pathList))
                .fetch()
                .stream().map(tuple -> {
                    PlatResourceResultDto result = new PlatResourceResultDto();
                    result.setTitle(tuple.get(qPlatResourcePo.title));
                    result.setPath(tuple.get(qPlatResourcePo.path));
                    result.setIconSvg(tuple.get(qPlatResourcePo.iconSvg));
                    return result;
        }).collect(Collectors.toList());
    }

    @Override
    public List<OrgResourceRelDto> readAllExpertModuleData() {

        QPlatResourcePo qPlatResourcePo = QPlatResourcePo.platResourcePo;

        return jpaQueryFactory.select(
                qPlatResourcePo.id,
                qPlatResourcePo.parentId,
                qPlatResourcePo.code,
                qPlatResourcePo.title,
                qPlatResourcePo.type,
                qPlatResourcePo.classify,
                qPlatResourcePo.serviceClassify,
                qPlatResourcePo.path,
                qPlatResourcePo.sortNum,
                qPlatResourcePo.iconSvg,
                qPlatResourcePo.tags,
                qPlatResourcePo.description
        )
                .from(qPlatResourcePo)
                .where(qPlatResourcePo.classify.eq(ComConstant.ModuleTerminal.EXPERT))
                .where(qPlatResourcePo.type.eq(ComConstant.ModuleType.MODULE_MENU))
                .fetch()
                .stream().map(tuple -> {
                    return new OrgResourceRelDto(
                            true,
                            true,
                            tuple.get(qPlatResourcePo.id),
                            tuple.get(qPlatResourcePo.parentId),
                            tuple.get(qPlatResourcePo.code),
                            tuple.get(qPlatResourcePo.title),
                            tuple.get(qPlatResourcePo.type),
                            tuple.get(qPlatResourcePo.classify),
                            tuple.get(qPlatResourcePo.serviceClassify),
                            tuple.get(qPlatResourcePo.path),
                            tuple.get(qPlatResourcePo.sortNum),
                            tuple.get(qPlatResourcePo.iconSvg),
                            tuple.get(qPlatResourcePo.tags),
                            tuple.get(qPlatResourcePo.description)
                    );
                }).collect(Collectors.toList());
    }

    @Override
    public Set<String> readAllExpertModuleCodeData() {
        QPlatResourcePo qPlatResourcePo = QPlatResourcePo.platResourcePo;
        return new HashSet<>(jpaQueryFactory.select(qPlatResourcePo.code)
                .from(qPlatResourcePo)
                .where(qPlatResourcePo.classify.eq(ComConstant.ModuleTerminal.EXPERT))
                .where(qPlatResourcePo.type.eq(ComConstant.ModuleType.MODULE_MENU))
                .fetch());
    }
}